package com.pclong.fightlandlordserver.util;

import com.pclong.fightlandlordserver.data.HibernateSessionFactory;
import com.pclong.fightlandlordserver.data.metadata.GlobalConfig;
import com.pclong.fightlandlordserver.data.metadata.GlobalConfigDAO;
import com.pclong.fightlandlordserver.game.model.AbstractModel;
import com.pclong.fightlandlordserver.game.model.GameConfigureConstant;
import com.pclong.fightlandlordserver.game.model.Lobby;
import com.pclong.fightlandlordserver.game.model.Platform;
import com.pclong.fightlandlordserver.game.model.Player;
import com.pclong.fightlandlordserver.game.model.Room;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.mina.core.session.IoSession;
import org.hibernate.Query;

import com.thoughtworks.xstream.XStream;

public class ModelUtil {

    private static Set<IoSession> sessions;
    private static String modelDesc;
    private static Platform platform;
    private static boolean isLocalDataBase;
    private static Map<String, Lobby> lobbys = Collections.synchronizedMap(new HashMap<String, Lobby>());
    private static Map<String, Room> rooms = Collections.synchronizedMap(new HashMap<String, Room>());
    private static Map<String, String> systemParameters = new HashMap<String, String>();
    private static Map<String, String> customPokersParameters = new HashMap<String, String>(); // TODO This variable should be moved to another TBD place!!!

    /**
     * 
     */
    public static void resetModels() {
        sessions = null;
        modelDesc = null;
        platform = null;
        lobbys = Collections.synchronizedMap(new HashMap<String, Lobby>());
        rooms = Collections.synchronizedMap(new HashMap<String, Room>());
        systemParameters = new HashMap<String, String>();
        customPokersParameters = new HashMap<String, String>();
        load();
        /*platform=new Platform();
        platform.setId("1");
        platform.setName("1");
        Lobby lb=new Lobby();
        lb.setId("1");
        lb.setName("1");
        lb.setParent(platform);
        lobbys.put("1",lb);
        lb=new Lobby();
        lb.setId("2");
        lb.setName("2");
        lb.setParent(platform);
        lobbys.put("2",lb);
        
        Room  rm=new Room();
        rm.setId("1");
        rm.setName("1");
        rm.setHighLevelMark("3");
        rm.setMidLevelMark("2");
        rm.setLowLevelMark("1");
        rm.setMinMarks("0");
        rm.setParent(lobbys.get("1"));
        
        rm=new Room();
        rm.setId("2");
        rm.setName("2");
        rm.setHighLevelMark("3");
        rm.setMidLevelMark("2");
        rm.setLowLevelMark("1");
        rm.setMinMarks("0");
        rm.setParent(lobbys.get("1"));*/
    }

    /**
     * @return
     */
    public static Set<IoSession> getSessions() {
        return sessions;
    }

    /**
     * @param sessionSet
     */
    public static void setSessions(Set<IoSession> sessionSet) {
        sessions = sessionSet;
    }

    static {
        load();
//        resetModels();//构造数据，将上面的注释掉
    }

    /**
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void load() {
        String local = PropertiesHelper.getProperty("tankweb.properties", "isLocalDataBase");
        ModelUtil.isLocalDataBase = ConvertUtil.toBoolean(local, false);
        // 获取配置信息
        //Properties config = readProperties();
//        tring xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\"><properties> <entry key=\"PLATFORM\">id=1,parentId=-1,name=ddzplatform,displayIndex=1,modelCategory=platform,disabled=false,childLimit=1</entry> <entry key=\"LOBBY\">id=1,parentId=1,name=ddzlobby,displayIndex=1,modelCategory=LOBBY,disabled=false,childLimit=12</entry>	<entry key=\"ROOM\">id=1,parentId=1,name=ROOM1,displayIndex=1,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=2,parentId=1,name=ROOM2,displayIndex=2,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=3,parentId=1,name=ROOM3,displayIndex=3,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=4,parentId=1,name=ROOM4,displayIndex=4,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=5,parentId=1,name=ROOM5,displayIndex=5,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=6,parentId=1,name=ROOM6,displayIndex=6,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=7,parentId=1,name=ROOM7,displayIndex=7,modelCategory=ROOM,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3</entry></properties>";
//       String xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\"><properties> <entry key=\"PLATFORM\">id=1,parentId=-1,name=ddzplatform,displayIndex=1,disabled=false,childLimit=1</entry> <entry key=\"LOBBY\">id=1,parentId=1,name=ddzlobby,displayIndex=1,disabled=false,childLimit=12</entry>	<entry key=\"ROOM\">id=1,parentId=1,name=ROOM1,displayIndex=1,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=2,parentId=1,name=ROOM2,displayIndex=2,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=3,parentId=1,name=ROOM3,displayIndex=3,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=4,parentId=1,name=ROOM4,displayIndex=4,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=5,parentId=1,name=ROOM5,displayIndex=5,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=6,parentId=1,name=ROOM6,displayIndex=6,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=7,parentId=1,name=ROOM7,displayIndex=7,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3</entry></properties>";
//         String xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\"><properties> <entry key=\"PLATFORM\">id=1,parentId=-1,name=ddzplatform,displayIndex=1,disabled=false</entry> <entry key=\"LOBBY\">id=1,parentId=1,name=ddzlobby,displayIndex=1,disabled=false2</entry>	<entry key=\"ROOM\">id=1,parentId=1,name=ROOM1,displayIndex=1,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=2,parentId=1,name=ROOM2,displayIndex=2,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=3,parentId=1,name=ROOM3,displayIndex=3,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=4,parentId=1,name=ROOM4,displayIndex=4,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=5,parentId=1,name=ROOM5,displayIndex=5,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=6,parentId=1,name=ROOM6,displayIndex=6,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3;id=7,parentId=1,name=ROOM7,displayIndex=7,disabled=false,childLimit=3,lowLevelMark=1,midLevelMark=2,highLevelMark=3</entry></properties>";
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\"><properties> <entry key=\"PLATFORM\">id=1,parentId=-1,name=ddzplatform,displayIndex=1,disabled=false</entry> <entry key=\"LOBBY\">id=1,parentId=1,name=ddzlobby,displayIndex=1,disabled=false2</entry>	<entry key=\"ROOM\">id=1,parentId=1,name=ROOM1,displayIndex=1,disabled=false;id=2,parentId=1,name=ROOM2,displayIndex=2,disabled=false;id=3,parentId=1,name=ROOM3,displayIndex=3,disabled=false;id=4,parentId=1,name=ROOM4,displayIndex=4,disabled=false;id=5,parentId=1,name=ROOM5,displayIndex=5,disabled=false;id=6,parentId=1,name=ROOM6,displayIndex=6,disabled=false;id=7,parentId=1,name=ROOM7,displayIndex=7,disabled=false</entry></properties>";
        Properties config = new Properties();
        try {
            config.loadFromXML(new ByteArrayInputStream(xml.getBytes("utf-8")));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String platformConfig = config.getProperty("PLATFORM");
        String[] lobbyConfigArray = config.getProperty("LOBBY").split(";");
        String[] roomConfigArray = config.getProperty("ROOM").split(";");
        int maxPlayerNumber = 100;// Integer.parseInt(config.getProperty("MAX_PLAYER_NUMBER"));

        // 创建模型
        platform = ModelUtil.createFromConfigString(Platform.class, platformConfig);
        for (String lobbyConfig : lobbyConfigArray) {
            Lobby lobby = ModelUtil.createFromConfigString(Lobby.class, lobbyConfig);
            if (lobby != null) {
                lobby.setParentId(platform.getId());
                lobby.setParent(platform);
                platform.addChild(lobby.getId(), lobby);
                lobbys.put(lobby.getId(), lobby);
            }

        }
        for (String roomConfig : roomConfigArray) {
            Room room = ModelUtil.createFromConfigString(Room.class, roomConfig, "parent");
            if (room != null) {
                if (lobbys.get(room.getParentId()) != null) {
                    room.setParent(platform.getChild(room.getParentId()));
                    room.setChildLimit(maxPlayerNumber);
                    platform.getChild(room.getParentId()).addChild(room.getId(), room);
                    rooms.put(room.getId(), room);
                }

            }

        }
        if (!ModelUtil.isLocalDataBase) {
            // 创建模型XML
            XStream stream = new XStream();
            stream.alias("platform", Platform.class);
            stream.alias("lobby", Lobby.class);
            stream.alias("room", Room.class);
            stream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);
            modelDesc = "<e4x-data>#</e4x-data>".replace("#", stream.toXML(platform));

            // 初始化系统参数
            for (GlobalConfig eachParameter : new GlobalConfigDAO().findByType(GameConfigureConstant.SERVER_PARAM_NAME)) {
                systemParameters.put(eachParameter.getName(), eachParameter.getValue());
            }

            // 初始化系统参数
            for (GlobalConfig eachParameter : new GlobalConfigDAO().findByType("CUSTOM_POKER")) {
                customPokersParameters.put(eachParameter.getName(), eachParameter.getValue());
            }
        }

    }

    public static final String getModelDesc() {
        return modelDesc;
    }

    /**
     * @param key
     * @param defaultValue
     * 
     * @return the systemParameters
     */
    public static String getSystemParameter(String key, Object defaultValue) {
        return getSystemParameter(key) == null ? defaultValue.toString() : getSystemParameter(key);
    }

    /**
     * @param key
     * 
     * @return the systemParameters
     */
    public static String getSystemParameter(String key) {
        return systemParameters.get(key);
    }

    /**
     * @param prefix
     * 
     * @return the systemParameters
     */
    public static List<String> getSystemParameters(String prefix) {
        List<String> results = new ArrayList<String>();
        for (Entry<String, String> entry : customPokersParameters.entrySet()) {
            if (entry.getKey().indexOf(prefix) == 0) {
                results.add(entry.getValue());
            }
        }
        return results;
    }

    /**
     * @return
     */
    public static final Platform getPlatform() {
        return platform;
    }

    /**
     * @param lobbyId
     * @return
     */
    public static Lobby getLobby(String lobbyId) {
        return lobbys.get(lobbyId);
    }

    /**
     * @param roomId
     * @return
     */
    public static Room getRoom(String roomId) {
        return rooms.get(roomId);
    }

    /**
     * @param session
     * @return
     */
    public static synchronized Player getPlayer(IoSession session) {
        return (Player) session.getAttribute(Player.ATTR_NAME);
    }

    /**
     * @param session
     * @return
     */
    public static synchronized void setPlayer(IoSession session, Player player) {
        session.setAttribute(Player.ATTR_NAME, player);
        player.setIosession(session);
    }

    /**
     * 从数据库中读取配置文件内容
     * 
     * @return Properties类型对象
     */
    private static Properties readProperties() {
        Properties properties = new Properties();
        try {
            Query query = HibernateSessionFactory.getSession().createQuery("from GlobalConfig where name = '" + GameConfigureConstant.GLOBAL_CONFIG_NAME + "' order by createTime desc");
            GlobalConfig config = (GlobalConfig) query.uniqueResult();
            if (config != null) {
                properties.loadFromXML(new ByteArrayInputStream(config.getValue().getBytes("utf-8")));
            }
            return properties;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param <T>
     * @param modelClass
     * @param configString
     * @return
     */
    private static <T extends AbstractModel<?, ?>> T createFromConfigString(Class<T> modelClass, String configString) {
        return createFromConfigString(modelClass, configString, null);
    }

    /**
     * @param <T>
     * @param modelClass
     * @param configString
     * @param exclusion
     * @return
     */
    private static <T extends AbstractModel<?, ?>> T createFromConfigString(Class<T> modelClass, String configString, String exclusion) {
        T bean;
        try {
            bean = modelClass.newInstance();
            String[] configProperties = configString.split(",");
            for (String currentConfig : configProperties) {
                String propName = currentConfig.split("=")[0];
                String propValue = currentConfig.split("=")[1];
                if (exclusion != null && exclusion.equals(propName)) {
                    continue;
                }
                PropertyUtils.setProperty(bean, propName, propValue);
            }
            return bean;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @return the isLocalDataBase
     */
    public static boolean isIsLocalDataBase() {
        return isLocalDataBase;
    }

    /**
     * @param aIsLocalDataBase the isLocalDataBase to set
     */
    public static void setIsLocalDataBase(boolean aIsLocalDataBase) {
        isLocalDataBase = aIsLocalDataBase;
    }

    /**
     * TODO This class my be used in the future
     *
     */
    public static class PuppetPool {

        private static final Map<String, Player> puppets = Collections.synchronizedSortedMap(new TreeMap<String, Player>());

        /**
         * @param puppetId
         * @return
         */
        public static Player getPuppet(String puppetId) {
            return puppets.get(puppetId);
        }

        /**
         * @param playerId
         * @param puppet
         */
        public static void addPuppet(String playerId, Player puppet) {
            puppets.put(playerId, puppet);
        }

        /**
         * @param playerId
         */
        public static void removePuppet(String playerId) {
            puppets.remove(playerId);
        }
    }
}
